using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;

namespace MLTimeline.Editor
{
    public class RulerView : VisualElement
    {
        public double Zoom { get; private set; } = 1.0;
        public double ScrollX { get; private set; } = 0.0;
        public int CurrentFrame { get; private set; } = 0;
        public ScrollView TrackPlatePanel => _trackPlatePanel;

        // 总帧数，定义了Slider的合法范围，例如 0-3000
        private int _totalFrames = 50000;
        public int TotalFrames
        {
            get => _totalFrames;
            set
            {
                _totalFrames = Math.Max(100, value); // 至少给一个合理的范围
                // 当总范围变化时，需要重置视图和滑块
                InitializeSliderAndZoom();
                Refresh();
            }
        }

        private static readonly int[] TickLevels = { 1, 5, 10, 30, 150, 300, 900, 1800, 9000, 18000, 54000, 108000, 648000, 2592000, 18144000 };
        private const int MaxTickLevel = 270000000;
        private const float MinLabelPixelSpacing = 60.0f;
        private const float TickShowStartSpacing = 4.0f;
        private const float TickFullHeightSpacing = 80.0f;
        private const double BasePixelsPerFrame = 20.0;
        private const int ContentOffsetX = 10;
        private readonly Color _tickColor = new Color(0f, 0f, 0f, 0.75f);
        private readonly Color _trackTickMajorColor = new Color(0.5f, 0.5f, 0.5f, 0.5f);

        private VisualElement _tickPanel;
        private ScrollView _trackPlatePanel;
        private VisualElement _labelContainer;
        private readonly List<Label> _activeLabels = new List<Label>();
        private readonly List<Label> _pooledLabels = new List<Label>();
        private VisualElement _playhead;
        private VisualElement _playheadHandle;
        private Label _playheadTooltip;
        private VisualElement _endhead;
        private MinMaxSlider _slider;
        private TickHandler _tickHandler;
        private bool _isPanning = false;
        private bool _isDraggingPlayhead = false;
        private Vector2 _panStartPosition;

        // 添加一个标志位，防止在代码更新滑块时，又触发回调导致循环
        private bool _isUpdatingSliderFromView = false;

        public RulerView()
        {
            CreateGUI();
            schedule.Execute(Initialize);
        }

        public void AddTrackPlate()
        {
            _trackPlatePanel.Add(new TrackPlateView());
        }

        private void CreateGUI()
        {
            var loader = TimelineEditorLoader.Instance;
            if (loader == null)
            {
                Debug.LogWarning("当前加载器不存在。");
                return;
            }
            if (loader.rulerView == null)
            {
                Debug.LogWarning("ruler-view.uxml文件不存在，请检查下，是否将uxml文件拖入TimelineEditorLoader.cs文件的Inspector面板内。");
                return;
            }
            loader.rulerView.CloneTree(this);
            _tickPanel = this.Q("tick-panel");
            _trackPlatePanel = this.Q<ScrollView>("track-plate-panel");
            _labelContainer = this.Q("label-panel");
            _endhead = this.Q("endhead");
            _playhead = this.Q("playhead");
            _playheadTooltip = this.Q<Label>("playhead-tooltip");
            _playheadHandle = _playhead.Q("playhead-handle");
            _slider = this.Q<MinMaxSlider>("slider");

            _tickHandler = new TickHandler(TickLevels);

            _tickPanel.generateVisualContent += OnGenerateVisualContent;
            RegisterCallback<WheelEvent>(OnZoom);
            RegisterCallback<MouseDownEvent>(OnMouseDown);
            RegisterCallback<MouseMoveEvent>(OnMouseMove);
            RegisterCallback<MouseUpEvent>(OnMouseUp);
            RegisterCallback<GeometryChangedEvent>(OnGeometryChanged);
            _playheadHandle.RegisterCallback<MouseDownEvent>(OnPlayheadMouseDown);
            _slider.RegisterValueChangedCallback(OnSliderChanged);
        }

        private void Initialize()
        {
            this.StretchToParentSize();
            InitializeSliderAndZoom(); // 使用新方法初始化
            Refresh();
        }

        /// <summary>
        /// 初始化滑块和视图的初始缩放/偏移
        /// </summary>
        private void InitializeSliderAndZoom()
        {
            double viewWidth = resolvedStyle.width;
            if (viewWidth <= 0) viewWidth = 1000; // 在第一次布局前给一个默认值

            // 1. 设置Slider的极限范围
            _slider.lowLimit = 0;
            _slider.highLimit = _totalFrames;

            // 2. 将滑块设置为满范围
            _slider.SetValueWithoutNotify(new Vector2(0, _totalFrames));

            // 3. 根据您的描述，此时应该看到全部内容
            // 因此，计算出能容纳TotalFrames的初始Zoom值
            Zoom = viewWidth / (_totalFrames * BasePixelsPerFrame);
            ScrollX = 0; // 初始偏移为0
        }

        private void Refresh()
        {
            // 更新滑块状态以匹配视图（仅当视图由滚轮/平移改变时）
            UpdateSlider();

            // 刷新标尺和标签
            _tickPanel.MarkDirtyRepaint();
            UpdateLabels();

            // 更新播放头和剪辑位置
            UpdatePlayheadPosition();
            UpdateTrackPlateLayout();
        }

        // --- 核心修改 ---
        /// <summary>
        /// 当拖动MinMaxSlider时，根据您的新逻辑，更新视图的Zoom和ScrollX
        /// </summary>
        private void OnSliderChanged(ChangeEvent<Vector2> evt)
        {
            // 如果这个事件是由代码（例如滚轮缩放后更新滑块）触发的，则直接返回，避免无限循环
            if (_isUpdatingSliderFromView) return;

            double viewWidth = resolvedStyle.width;
            if (viewWidth <= 0) return;

            // 1. 获取滑块定义的新可见范围
            float startFrame = evt.newValue.x;
            float endFrame = evt.newValue.y;
            double visibleFrameRange = endFrame - startFrame;

            // 防止范围为0导致除法错误
            if (visibleFrameRange <= 0) return;

            // 2. 根据滑块范围计算新的缩放系数 (Zoom)
            // 逻辑：可见帧范围 * 每帧像素 * 缩放系数 = 视图宽度
            Zoom = viewWidth / (visibleFrameRange * BasePixelsPerFrame);

            // 3. 根据滑块的起始位置计算新的偏移 (ScrollX)
            // 逻辑：将视图的左侧 (pixel 0) 对齐到 startFrame
            // 从 FrameToPixel 公式反推: ScrollX = (frame * pixelsPerFrame * Zoom) - pixel
            // 我们希望 startFrame 在 0 像素位置 (忽略ContentOffsetX，它会在绘制时加上)
            ScrollX = startFrame * BasePixelsPerFrame * Zoom;

            // 4. 刷新整个视图来应用新的Zoom和ScrollX
            // 注意：这里的Refresh会调用UpdateSlider，但由于我们的逻辑是单向控制，
            // UpdateSlider会用相同的值再设置一遍滑块，所以不会有问题。
            Refresh();
        }

        /// <summary>
        /// 当视图因其他原因（滚轮、平移）改变时，反过来更新Slider的位置
        /// </summary>
        private void UpdateSlider()
        {
            double viewWidth = resolvedStyle.width;
            if (viewWidth <= 0) return;

            // 计算当前视图可见的帧范围
            float startFrame = (float)PixelToFrame(0);
            float endFrame = (float)PixelToFrame(viewWidth);

            // 设置标志位，告诉OnSliderChanged回调不要执行任何操作
            _isUpdatingSliderFromView = true;
            _slider.SetValueWithoutNotify(new Vector2(
                Mathf.Max(0, startFrame),
                Mathf.Min(_totalFrames, endFrame)
            ));
            // 操作完成后，立即取消标志位
            _isUpdatingSliderFromView = false;
        }

        private void OnZoom(WheelEvent evt)
        {
            double zoomFactor = evt.delta.y < 0 ? 1.15 : 1 / 1.15;

            // 计算缩放中心点对应的帧
            double frameAtMouse = PixelToFrame(evt.localMousePosition.x);

            // 更新Zoom值，但要限制在合理的范围内
            double maxZoom = resolvedStyle.width / (1 * BasePixelsPerFrame); // 假设最小能看到1帧
            double minZoom = resolvedStyle.width / (_totalFrames * BasePixelsPerFrame); // 最小能看到所有帧
            Zoom = Math.Clamp(Zoom * zoomFactor, minZoom, maxZoom);

            // 围绕鼠标位置进行缩放：保持frameAtMouse在屏幕上的位置不变
            ScrollX = (frameAtMouse * BasePixelsPerFrame * Zoom) - evt.localMousePosition.x;

            ClampScrollX();
            Refresh();
            evt.StopPropagation();
        }

        private void OnMouseMove(MouseMoveEvent evt)
        {
            if (_isPanning)
            {
                double deltaX = evt.mousePosition.x - _panStartPosition.x;
                ScrollX -= deltaX;
                _panStartPosition = evt.mousePosition;

                ClampScrollX();
                Refresh();
            }
            else if (_isDraggingPlayhead)
            {
                int newFrame = (int)Math.Round(PixelToFrame(evt.localMousePosition.x));
                SetCurrentFrame(newFrame);
            }
        }

        private void ClampScrollX()
        {
            if (ScrollX < 0) ScrollX = 0;

            // 最大滚动位置：保证视图右侧不会超过 totalFrames
            double totalContentWidth = _totalFrames * BasePixelsPerFrame * Zoom;
            double viewWidth = resolvedStyle.width;
            double maxScrollX = totalContentWidth - viewWidth;

            // 如果内容比视图还窄，则不允许滚动
            if (maxScrollX < 0) maxScrollX = 0;

            if (ScrollX > maxScrollX) ScrollX = maxScrollX;
        }

        // --- 以下方法基本保持不变 ---

        private void OnGenerateVisualContent(MeshGenerationContext context)
        {
            var painter = context.painter2D;
            double viewWidth = resolvedStyle.width;
            double viewHeight = resolvedStyle.height;
            double tickHeight = _tickPanel.resolvedStyle.height;

            if (viewWidth <= 0) return;

            // --- 1. 统一计算状态 ---
            double startFrame = PixelToFrame(0);
            double endFrame = PixelToFrame(viewWidth);
            _tickHandler.SetRanges(startFrame, endFrame, viewWidth);
            _tickHandler.CalculateTickStrengths(TickShowStartSpacing, TickFullHeightSpacing, true);

            painter.lineWidth = 1.0f;
            float maxTickHeight = (float)tickHeight * 0.7f;

            // --- 2. Pass 1: 绘制所有次级刻度 (不包括主刻度) ---
            int labelLevelIndex = _tickHandler.GetLevelForLabels(MinLabelPixelSpacing);
            for (int i = _tickHandler.BiggestTickIndex; i >= _tickHandler.SmallestTickIndex; i--)
            {
                if (i == labelLevelIndex) continue;

                float strength = _tickHandler.GetStrength(i);
                if (strength <= 0) continue;

                float currentHeight = maxTickHeight * strength;

                var ticks = _tickHandler.GetTicks(i, true);
                foreach (var frame in ticks)
                {
                    float xPos = (float)FrameToPixel(frame);
                    painter.strokeColor = _tickColor;
                    painter.BeginPath();
                    painter.MoveTo(new Vector2(xPos, (float)tickHeight - currentHeight));
                    painter.LineTo(new Vector2(xPos, (float)tickHeight));
                    painter.Stroke();
                }
            }

            // --- 3. Pass 2: 专门绘制主刻度及其延伸线 ---
            if (labelLevelIndex != -1)
            {
                float strength = _tickHandler.GetStrength(labelLevelIndex);
                if (strength > 0)
                {
                    float currentHeight = maxTickHeight * strength;
                    var ticks = _tickHandler.GetTicks(labelLevelIndex, false);
                    foreach (var frame in ticks)
                    {
                        float xPos = (float)FrameToPixel(frame);

                        painter.strokeColor = _tickColor;
                        painter.BeginPath();
                        painter.MoveTo(new Vector2(xPos, (float)tickHeight - currentHeight));
                        painter.LineTo(new Vector2(xPos, (float)tickHeight));
                        painter.Stroke();

                        painter.strokeColor = _trackTickMajorColor;
                        painter.BeginPath();
                        painter.MoveTo(new Vector2(xPos, (float)tickHeight));
                        painter.LineTo(new Vector2(xPos, (float)viewHeight));
                        painter.Stroke();
                    }
                }
            }
        }

        private void OnMouseDown(MouseDownEvent evt)
        {
            if (evt.button == 0)
            {
                int newFrame = (int)Math.Round(PixelToFrame(evt.localMousePosition.x));
                SetCurrentFrame(newFrame);
                _isDraggingPlayhead = true;
                _playheadTooltip.visible = true;
                this.CaptureMouse();
                evt.StopPropagation();
            }
            else if (evt.button == 2)
            {
                _isPanning = true;
                _panStartPosition = evt.mousePosition;
                this.CaptureMouse();
                evt.StopPropagation();
            }
        }

        private void OnMouseUp(MouseUpEvent evt)
        {
            if (evt.button == 2 && _isPanning)
            {
                _isPanning = false;
                this.ReleaseMouse();
                evt.StopPropagation();
            }
            else if (_isDraggingPlayhead && evt.button == 0)
            {
                _isDraggingPlayhead = false;
                _playheadTooltip.visible = false;
                this.ReleaseMouse();
                evt.StopPropagation();
            }
        }

        private void OnGeometryChanged(GeometryChangedEvent evt)
        {
            // 当视图尺寸变化时，需要重新计算初始状态和刷新
            InitializeSliderAndZoom();
            Refresh();
        }

        private void OnPlayheadMouseDown(MouseDownEvent evt)
        {
            if (evt.button == 0)
            {
                _isDraggingPlayhead = true;
                SetCurrentFrame(CurrentFrame);
                _playheadTooltip.visible = true;
                this.CaptureMouse();
                evt.StopPropagation();
            }
        }

        public void UpdateLabels()
        {
            foreach (var label in _activeLabels)
            {
                label.visible = false;
                _pooledLabels.Add(label);
            }
            _activeLabels.Clear();

            double viewWidth = resolvedStyle.width;
            if (viewWidth <= 0) return;

            double startFrame = PixelToFrame(0);
            double endFrame = PixelToFrame(viewWidth);
            _tickHandler.SetRanges(startFrame, endFrame, viewWidth);
            _tickHandler.CalculateTickStrengths(TickShowStartSpacing, TickFullHeightSpacing, true);

            for (int i = _tickHandler.SmallestTickIndex; i <= _tickHandler.BiggestTickIndex; i++)
            {
                double spacing = TickLevels[i] * viewWidth / (endFrame - startFrame);
                if (spacing < MinLabelPixelSpacing) continue;

                float strength = _tickHandler.GetStrength(i);
                if (strength <= 0.01f) continue;

                var ticks = _tickHandler.GetTicks(i, true);
                foreach (var frame in ticks)
                {
                    var label = GetPooledLabel();
                    label.text = frame.ToString();
                    label.style.fontSize = 11;
                    label.style.opacity = strength;

                    float xPos = (float)FrameToPixel(frame);
                    label.style.left = xPos + 3;
                    label.style.top = 2;
                }
            }
        }

        private void UpdateTrackPlateLayout()
        {
            var children = _trackPlatePanel.Children();
            foreach (var child in children)
            {
                if (child is TrackPlateView trackPlateView)
                {
                    var clipChildren = trackPlateView.ClipViews;
                    foreach (var clipChild in clipChildren)
                    {
                        if (clipChild is ClipView clipView)
                        {
                            float startPixel = (float)FrameToPixel(clipView.StartFrame);
                            float endPixel = (float)FrameToPixel(clipView.EndFrame);

                            float width = endPixel - startPixel;
                            clipView.style.left = startPixel;
                            clipView.style.width = width;
                        }
                    }
                }
            }
        }

        public void SetCurrentFrame(int frame)
        {
            // 注意这里我们用 TotalFrames 作为上限
            CurrentFrame = Math.Max(0, Math.Min(frame, _totalFrames));
            _playheadTooltip.text = CurrentFrame.ToString();
            UpdatePlayheadPosition();
        }

        private Label GetPooledLabel()
        {
            Label label;
            if (_pooledLabels.Count > 0)
            {
                label = _pooledLabels[^1];
                _pooledLabels.RemoveAt(_pooledLabels.Count - 1);
            }
            else
            {
                label = new Label { style = { position = Position.Absolute } };
                _labelContainer.Add(label);
            }
            label.visible = true;
            _activeLabels.Add(label);
            return label;
        }

        private void UpdatePlayheadPosition()
        {
            float pixelPos = (float)FrameToPixel(CurrentFrame);
            _playhead.style.left = pixelPos - (_playheadHandle.resolvedStyle.width / 2f);
            _playheadTooltip.style.left = _playhead.style.left;
        }

        private double FrameToPixel(double frame) => (frame * BasePixelsPerFrame * Zoom) - ScrollX + ContentOffsetX;
        private double PixelToFrame(double pixel) => (pixel - ContentOffsetX + ScrollX) / (BasePixelsPerFrame * Zoom);
    }
}